﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;

namespace RxjhServer.Network
{
	public class TcpServer
	{
		protected IntPtr _pServer = IntPtr.Zero;

		protected IntPtr pListener = IntPtr.Zero;

		protected bool IsCreate;

		private Sdk.OnPrepareListen _OnPrepareListen;

		private Sdk.OnAccept _OnAccept;

		private Sdk.OnReceive _OnReceive;

		private Sdk.OnSend _OnSend;

		private Sdk.OnClose _OnClose;

		private Sdk.OnShutdown _OnShutdown;

		protected IntPtr pServer
		{
			get
			{
				return this._pServer;
			}
			set
			{
				this._pServer = value;
			}
		}

		public string IpAddress
		{
			get;
			set;
		}

		public ushort Port
		{
			get;
			set;
		}

		public event TcpServerEvent.OnAcceptEventHandler OnAccept;

		public event TcpServerEvent.OnSendEventHandler OnSend;

		public event TcpServerEvent.OnPrepareListenEventHandler OnPrepareListen;

		public event TcpServerEvent.OnReceiveEventHandler OnReceive;

		public event TcpServerEvent.OnCloseEventHandler OnClose;

		public event TcpServerEvent.OnShutdownEventHandler OnShutdown;

		public TcpServer()
		{
			this.CreateListener();
		}

		~TcpServer()
		{
			this.Destroy();
		}

		protected virtual bool CreateListener()
		{
			if (this.IsCreate || this.pListener != IntPtr.Zero || this.pServer != IntPtr.Zero)
			{
				return false;
			}
			this.pListener = Sdk.Create_HP_TcpServerListener();
			if (this.pListener == IntPtr.Zero)
			{
				return false;
			}
			this.pServer = Sdk.Create_HP_TcpServer(this.pListener);
			if (this.pServer == IntPtr.Zero)
			{
				return false;
			}
			this.IsCreate = true;
			return true;
		}

		public virtual void Destroy()
		{
			this.Destroying();
			if (this.pServer != IntPtr.Zero)
			{
				Sdk.Destroy_HP_TcpServer(this.pServer);
				this.pServer = IntPtr.Zero;
			}
			if (this.pListener != IntPtr.Zero)
			{
				Sdk.Destroy_HP_TcpServerListener(this.pListener);
				this.pListener = IntPtr.Zero;
			}
			this.IsCreate = false;
		}

		public bool Start(int StartID)
		{
			if (!this.IsCreate)
			{
				return false;
			}
			if (this.IsStarted)
			{
				return false;
			}
			ushort serverID = (ushort)StartID;
			this.SetCallback();
			World.ServerIDStart++;
			return Sdk.HP_Server_Start(this.pServer, this.IpAddress, this.Port, serverID);
		}

		public bool Destroying()
		{
			return this.IsStarted && Sdk.HP_Server_Destroying(this.pServer);
		}

		public bool Stop()
		{
			return this.IsStarted && Sdk.HP_Server_Stop(this.pServer);
		}

		public bool Send(IntPtr connId, byte[] bytes, int size)
		{
			return Sdk.HP_Server_Send(this.pServer, connId, bytes, size);
		}

		public bool Send(IntPtr connId, IntPtr bufferPtr, int size)
		{
			return Sdk.HP_Server_Send(this.pServer, connId, bufferPtr, size);
		}

		public bool Send(IntPtr connId, byte[] bytes, int offset, int size)
		{
			return Sdk.HP_Server_SendPart(this.pServer, connId, bytes, size, offset);
		}

		public bool Send(IntPtr connId, IntPtr bufferPtr, int offset, int size)
		{
			return Sdk.HP_Server_SendPart(this.pServer, connId, bufferPtr, size, offset);
		}

		public bool Send<T>(IntPtr connId, T obj)
		{
			byte[] array = this.StructureToByte<T>(obj);
			return this.Send(connId, array, array.Length);
		}

		public bool SendBySerializable(IntPtr connId, object obj)
		{
			byte[] array = this.ObjectToBytes(obj);
			return this.Send(connId, array, array.Length);
		}

		public bool SendPackets(IntPtr connId, WSABUF[] pBuffers, int count)
		{
			return Sdk.HP_Server_SendPackets(this.pServer, connId, pBuffers, count);
		}

		public bool SendPackets<T>(IntPtr connId, T[] objects)
		{
			bool result = false;
			WSABUF[] array = new WSABUF[objects.Length];
			IntPtr[] array2 = new IntPtr[array.Length];
			try
			{
				for (int i = 0; i < objects.Length; i++)
				{
					array[i].Length = Marshal.SizeOf(typeof(T));
					array2[i] = Marshal.AllocHGlobal(array[i].Length);
					Marshal.StructureToPtr(objects[i], array2[i], true);
					array[i].Buffer = array2[i];
				}
				result = this.SendPackets(connId, array, array.Length);
			}
			catch (Exception ex)
			{
				throw ex;
			}
			finally
			{
				for (int j = 0; j < array2.Length; j++)
				{
					if (array2[j] != IntPtr.Zero)
					{
						Marshal.FreeHGlobal(array2[j]);
					}
				}
			}
			return result;
		}

		public bool SendSmallFile(IntPtr connId, string filePath, ref WSABUF head, ref WSABUF tail)
		{
			return Sdk.HP_TcpServer_SendSmallFile(this.pServer, connId, filePath, ref head, ref tail);
		}

		public bool SendSmallFile(IntPtr connId, string filePath, byte[] head, byte[] tail)
		{
			IntPtr zero = IntPtr.Zero;
			IntPtr zero2 = IntPtr.Zero;
			WSABUF wSABUF = new WSABUF
			{
				Length = 0,
				Buffer = zero
			};
			WSABUF wSABUF2 = new WSABUF
			{
				Length = 0,
				Buffer = zero2
			};
			if (head != null)
			{
				wSABUF.Length = head.Length;
				wSABUF.Buffer = Marshal.UnsafeAddrOfPinnedArrayElement(head, 0);
			}
			if (tail != null)
			{
				wSABUF.Length = tail.Length;
				wSABUF.Buffer = Marshal.UnsafeAddrOfPinnedArrayElement(tail, 0);
			}
			return this.SendSmallFile(connId, filePath, ref wSABUF, ref wSABUF2);
		}

		public bool SendSmallFile<T1, T2>(IntPtr connId, string filePath, T1 head, T2 tail)
		{
			byte[] head2 = null;
			if (head != null)
			{
				head2 = this.StructureToByte<T1>(head);
			}
			byte[] tail2 = null;
			if (tail != null)
			{
				tail2 = this.StructureToByte<T2>(tail);
			}
			return this.SendSmallFile(connId, filePath, head2, tail2);
		}

		public bool Disconnect(IntPtr connId, bool force)
		{
			return Sdk.HP_Server_Disconnect(this.pServer, connId, force);
		}

		public bool DisconnectLongConnections(uint period, bool force)
		{
			return Sdk.HP_Server_DisconnectLongConnections(this.pServer, period, force);
		}

		public bool DisconnectSilenceConnections(uint period, bool force)
		{
			return Sdk.HP_Server_DisconnectSilenceConnections(this.pServer, period, force);
		}

		public bool GetLocalAddress(IntPtr connId, ref string ip, ref ushort port)
		{
			int num = 40;
			StringBuilder stringBuilder = new StringBuilder(num);
			bool flag = Sdk.HP_Server_GetLocalAddress(this.pServer, connId, stringBuilder, ref num, ref port) && num > 0;
			if (flag)
			{
				ip = stringBuilder.ToString();
			}
			return flag;
		}

		public bool GetRemoteAddress(IntPtr connId, ref string ip, ref ushort port)
		{
			int num = 40;
			StringBuilder stringBuilder = new StringBuilder(num);
			bool flag = Sdk.HP_Server_GetRemoteAddress(this.pServer, connId, stringBuilder, ref num, ref port) && num > 0;
			if (flag)
			{
				ip = stringBuilder.ToString();
			}
			return flag;
		}

		public bool GetPendingDataLength(IntPtr connId, ref int length)
		{
			return Sdk.HP_Server_GetPendingDataLength(this.pServer, connId, ref length);
		}

		public bool SetConnectionExtra(IntPtr connId, object obj)
		{
			IntPtr intPtr = IntPtr.Zero;
			if (Sdk.HP_Server_GetConnectionExtra(this.pServer, connId, ref intPtr) && intPtr != IntPtr.Zero)
			{
				Marshal.FreeHGlobal(intPtr);
				intPtr = IntPtr.Zero;
			}
			if (obj != null)
			{
				intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
				Marshal.StructureToPtr(obj, intPtr, false);
			}
			return Sdk.HP_Server_SetConnectionExtra(this.pServer, connId, intPtr);
		}

		public bool GetConnectionExtra(IntPtr connId, ref IntPtr ptr)
		{
			return Sdk.HP_Server_GetConnectionExtra(this.pServer, connId, ref ptr) && ptr != IntPtr.Zero;
		}

		public bool IsStarted
		{
			get
			{
				return !(this.pServer == IntPtr.Zero) && Sdk.HP_Server_HasStarted(this.pServer);
			}
		}

		public ServiceState State
		{
			get
			{
				return Sdk.HP_Server_GetState(this.pServer);
			}
		}

		public uint ConnectionCount
		{
			get
			{
				return Sdk.HP_Server_GetConnectionCount(this.pServer);
			}
		}

		public IntPtr[] GetAllConnectionIDs()
		{
			IntPtr[] array = null;
			uint connectionCount;
			do
			{
				connectionCount = this.ConnectionCount;
				if (connectionCount == 0u)
				{
					return array;
				}
				array = new IntPtr[connectionCount];
			}
			while (!Sdk.HP_Server_GetAllConnectionIDs(this.pServer, array, ref connectionCount));
			if ((long)array.Length > (long)((ulong)connectionCount))
			{
				IntPtr[] array2 = new IntPtr[connectionCount];
				Array.Copy(array, array2, (long)((ulong)connectionCount));
				array = array2;
			}
			return array;
		}

		public bool GetListenAddress(ref string ip, ref ushort port)
		{
			int capacity = 40;
			StringBuilder stringBuilder = new StringBuilder(capacity);
			bool flag = Sdk.HP_Server_GetListenAddress(this.pServer, stringBuilder, ref capacity, ref port);
			if (flag)
			{
				ip = stringBuilder.ToString();
			}
			return flag;
		}

		public bool GetConnectPeriod(IntPtr connId, ref uint period)
		{
			return Sdk.HP_Server_GetConnectPeriod(this.pServer, connId, ref period);
		}

		public bool GetSilencePeriod(IntPtr connId, ref uint period)
		{
			return Sdk.HP_Server_GetSilencePeriod(this.pServer, connId, ref period);
		}

		public uint WorkerThreadCount
		{
			get
			{
				return Sdk.HP_Server_GetWorkerThreadCount(this.pServer);
			}
			set
			{
				Sdk.HP_Server_SetWorkerThreadCount(this.pServer, value);
			}
		}

		public uint AcceptSocketCount
		{
			get
			{
				return Sdk.HP_TcpServer_GetAcceptSocketCount(this.pServer);
			}
			set
			{
				Sdk.HP_TcpServer_SetAcceptSocketCount(this.pServer, value);
			}
		}

		public uint SocketBufferSize
		{
			get
			{
				return Sdk.HP_TcpServer_GetSocketBufferSize(this.pServer);
			}
			set
			{
				Sdk.HP_TcpServer_SetSocketBufferSize(this.pServer, value);
			}
		}

		public uint SocketListenQueue
		{
			get
			{
				return Sdk.HP_TcpServer_GetSocketListenQueue(this.pServer);
			}
			set
			{
				Sdk.HP_TcpServer_SetSocketListenQueue(this.pServer, value);
			}
		}

		public uint FreeSocketObjLockTime
		{
			get
			{
				return Sdk.HP_Server_GetFreeSocketObjLockTime(this.pServer);
			}
			set
			{
				Sdk.HP_Server_SetFreeSocketObjLockTime(this.pServer, value);
			}
		}

		public uint FreeSocketObjPool
		{
			get
			{
				return Sdk.HP_Server_GetFreeSocketObjPool(this.pServer);
			}
			set
			{
				Sdk.HP_Server_SetFreeSocketObjPool(this.pServer, value);
			}
		}

		public uint FreeSocketObjHold
		{
			get
			{
				return Sdk.HP_Server_GetFreeSocketObjHold(this.pServer);
			}
			set
			{
				Sdk.HP_Server_SetFreeSocketObjHold(this.pServer, value);
			}
		}

		public uint FreeBufferObjPool
		{
			get
			{
				return Sdk.HP_Server_GetFreeBufferObjPool(this.pServer);
			}
			set
			{
				Sdk.HP_Server_SetFreeBufferObjPool(this.pServer, value);
			}
		}

		public uint FreeBufferObjHold
		{
			get
			{
				return Sdk.HP_Server_GetFreeBufferObjHold(this.pServer);
			}
			set
			{
				Sdk.HP_Server_SetFreeBufferObjHold(this.pServer, value);
			}
		}

		public uint KeepAliveTime
		{
			get
			{
				return Sdk.HP_TcpServer_GetKeepAliveTime(this.pServer);
			}
			set
			{
				Sdk.HP_TcpServer_SetKeepAliveTime(this.pServer, value);
			}
		}

		public uint KeepAliveInterval
		{
			get
			{
				return Sdk.HP_TcpServer_GetKeepAliveInterval(this.pServer);
			}
			set
			{
				Sdk.HP_TcpServer_SetKeepAliveInterval(this.pServer, value);
			}
		}

		public bool MarkSilence
		{
			get
			{
				return Sdk.HP_Server_IsMarkSilence(this.pServer);
			}
			set
			{
				Sdk.HP_Server_SetMarkSilence(this.pServer, value);
			}
		}

		public SendPolicy SendPolicy
		{
			get
			{
				return Sdk.HP_Server_GetSendPolicy(this.pServer);
			}
			set
			{
				Sdk.HP_Server_SetSendPolicy(this.pServer, value);
			}
		}

		public int SYSGetLastError()
		{
			return Sdk.SYS_GetLastError();
		}

		public int SYSWSAGetLastError()
		{
			return Sdk.SYS_WSAGetLastError();
		}

		public SocketError ErrorCode
		{
			get
			{
				return Sdk.HP_Server_GetLastError(this.pServer);
			}
		}

		public string ErrorMessage
		{
			get
			{
				IntPtr ptr = Sdk.HP_Server_GetLastErrorDesc(this.pServer);
				return Marshal.PtrToStringUni(ptr);
			}
		}

		protected virtual void SetCallback()
		{
			this._OnPrepareListen = new Sdk.OnPrepareListen(this.SDK_OnPrepareListen);
			this._OnAccept = new Sdk.OnAccept(this.SDK_OnAccept);
			this._OnSend = new Sdk.OnSend(this.SDK_OnSend);
			this._OnReceive = new Sdk.OnReceive(this.SDK_OnReceive);
			this._OnClose = new Sdk.OnClose(this.SDK_OnClose);
			this._OnShutdown = new Sdk.OnShutdown(this.SDK_OnShutdown);
			Sdk.HP_Set_FN_Server_OnPrepareListen(this.pListener, this._OnPrepareListen);
			Sdk.HP_Set_FN_Server_OnAccept(this.pListener, this._OnAccept);
			Sdk.HP_Set_FN_Server_OnSend(this.pListener, this._OnSend);
			Sdk.HP_Set_FN_Server_OnReceive(this.pListener, this._OnReceive);
			Sdk.HP_Set_FN_Server_OnClose(this.pListener, this._OnClose);
			Sdk.HP_Set_FN_Server_OnShutdown(this.pListener, this._OnShutdown);
		}

		protected HandleResult SDK_OnPrepareListen(IntPtr soListen)
		{
			if (this.OnPrepareListen != null)
			{
				return this.OnPrepareListen(soListen);
			}
			return HandleResult.Ignore;
		}

		protected HandleResult SDK_OnAccept(IntPtr connId, IntPtr pClient)
		{
			if (this.OnAccept != null)
			{
				return this.OnAccept(connId, pClient);
			}
			return HandleResult.Ignore;
		}

		protected HandleResult SDK_OnSend(IntPtr connId, IntPtr pData, int length)
		{
			if (this.OnSend != null)
			{
				byte[] array = new byte[length];
				Marshal.Copy(pData, array, 0, length);
				return this.OnSend(connId, array);
			}
			return HandleResult.Ignore;
		}

		protected HandleResult SDK_OnReceive(IntPtr connId, IntPtr pData, int length)
		{
			if (this.OnReceive != null)
			{
				byte[] array = new byte[length];
				Marshal.Copy(pData, array, 0, length);
				return this.OnReceive(connId, array);
			}
			return HandleResult.Ignore;
		}

		protected HandleResult SDK_OnClose(IntPtr connId, SocketOperation enOperation, int errorCode)
		{
			if (this.OnClose != null)
			{
				return this.OnClose(connId, enOperation, errorCode);
			}
			return HandleResult.Ignore;
		}

		protected HandleResult SDK_OnShutdown()
		{
			if (this.OnShutdown != null)
			{
				return this.OnShutdown();
			}
			return HandleResult.Ignore;
		}

		public string GetSocketErrorDesc(SocketError code)
		{
			IntPtr ptr = Sdk.HP_GetSocketErrorDesc(code);
			return Marshal.PtrToStringUni(ptr);
		}

		public int SYS_SetSocketOption(IntPtr sock, int level, int name, IntPtr val, int len)
		{
			return Sdk.SYS_SetSocketOption(sock, level, name, val, len);
		}

		public int SYSGetSocketOption(IntPtr sock, int level, int name, IntPtr val, ref int len)
		{
			return Sdk.SYS_GetSocketOption(sock, level, name, val, ref len);
		}

		public int SYSIoctlSocket(IntPtr sock, long cmd, IntPtr arg)
		{
			return Sdk.SYS_IoctlSocket(sock, cmd, arg);
		}

		public int SYS_WSAIoctl(IntPtr sock, uint dwIoControlCode, IntPtr lpvInBuffer, uint cbInBuffer, IntPtr lpvOutBuffer, uint cbOutBuffer, uint lpcbBytesReturned)
		{
			return Sdk.SYS_WSAIoctl(sock, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned);
		}

		public byte[] StructureToByte<T>(T structure)
		{
			int num = Marshal.SizeOf(typeof(T));
			byte[] array = new byte[num];
			IntPtr intPtr = Marshal.AllocHGlobal(num);
			try
			{
				Marshal.StructureToPtr(structure, intPtr, true);
				Marshal.Copy(intPtr, array, 0, num);
			}
			finally
			{
				Marshal.FreeHGlobal(intPtr);
			}
			return array;
		}

		public T ByteToStructure<T>(byte[] dataBuffer)
		{
			object obj = null;
			int num = Marshal.SizeOf(typeof(T));
			IntPtr intPtr = Marshal.AllocHGlobal(num);
			try
			{
				Marshal.Copy(dataBuffer, 0, intPtr, num);
				obj = Marshal.PtrToStructure(intPtr, typeof(T));
			}
			finally
			{
				Marshal.FreeHGlobal(intPtr);
			}
			return (T)((object)obj);
		}

		public byte[] ObjectToBytes(object obj)
		{
			byte[] buffer;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				IFormatter formatter = new BinaryFormatter();
				formatter.Serialize(memoryStream, obj);
				buffer = memoryStream.GetBuffer();
			}
			return buffer;
		}
	}
}
